﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel;

using InfFront.UICore;

namespace InfFront.InfoViews.Base
{
    public class InfoViewEntry: IEditableObject, IIconedObject, IDisposable
    {
        #region Private variables
        InfoViewSource owner;
        InfoViewRecord record;
        List<InfoViewEntryField> fields = null;
        bool isFrozen = false;
        #endregion Private variables;

        #region Internal Interface

        internal InfoViewEntry(InfoViewSource owner, InfoViewRecord record)
        {
            this.owner = owner;
            this.record = record;
        }

        internal InfoViewSource Owner
        {
            get { return owner; }
        }

        internal IInfoEntry Origin
        {
            get { return record.Origin; }
        }

        public bool NeedsEditBuffer
        {
            get { return Owner.NeedsEditBuffer; }
        }

        public object GetFieldValue(InfoViewField field)
        {
            Debug.Assert(field != null);
            return record.GetFieldValue(field);
        }

        public object GetDisplayFieldValue(InfoViewField field)
        {
            Debug.Assert(field != null);
            return record.GetDisplayFieldValue(field);
        }

        public void SetFieldValue(InfoViewField field, object value)
        {
            Debug.Assert(field != null);
            if (IsFrozen)
                return;
            record.SetFieldValue(field, value);
        }

        public object GetFieldValue(string name)
        {
            return GetFieldValue(owner.FieldByName(name));
        }

        public void SetFieldValue(string name, object value)
        {
            SetFieldValue(owner.FieldByName(name), value);
        }

        #endregion Internal Interface

        public override string ToString()
        {
            return record.ToString();
        }

        public IVisualSettingsAccessor VisualSettings
        {
            get { return owner.VisualSettings; }
        }

        public event EventHandler OnRefreshed
        {
            add { owner.OnRebuilt += value; }
            remove { owner.OnRebuilt -= value; }
        }

        public IEnumerable<InfoViewEntryField> Fields
        {
            get
            {
                if (fields == null)
                {
                    fields = new List<InfoViewEntryField>();
                    foreach (var fld in owner.Fields)
                        fields.Add(new InfoViewEntryField(this, fld));
                }
                return fields;
            }
        }

        public IEnumerable<InfoViewEntryField> UngrouppedEditableFields
        {
            get
            {
                foreach (var fld in Fields)
                {
                    if (!fld.IsReadOnly && !fld.HasEditGroup)
                        yield return fld;
                }
            }
        }

        public IEnumerable<InfoViewEntryFieldGroup> EditGroups
        {
            get
            {
                foreach (var grp in owner.EditFieldGroups)
                    yield return new InfoViewEntryFieldGroup(this, grp);
            }
        }

        void record_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            foreach (var fld in fields)
            {
                if (fld.Name == e.PropertyName)
                {
                    fld.FireValuePropertyChanged();
                    break;
                }
            }
        }

        public bool IsFrozen
        {
            get { return isFrozen; }
            set { isFrozen = true; }
        }

        public class FreezeState : IDisposable
        {
            InfoViewEntry entry = null;
            bool prevState;
            public FreezeState(InfoViewEntry entry)
            {
                this.entry = entry;
                this.prevState = entry.IsFrozen;
                entry.IsFrozen = true;
            }

            #region IDisposable Members

            public void Dispose()
            {
                entry.IsFrozen = prevState;
                entry = null;
            }

            #endregion
        }

        #region IEditableObject Members

        public void BeginEdit()
        {
            record.BeginEdit();
            record.PropertyChanged += record_PropertyChanged;
        }

        public void CancelEdit()
        {
            record.CancelEdit();
            record.PropertyChanged -= record_PropertyChanged;
        }

        public void EndEdit()
        {
            record.EndEdit();
            record.PropertyChanged -= record_PropertyChanged;
        }

        public void ApplyEdit()
        {
            record.ApplyEdit();
        }

        #endregion

        #region IIconedObject Members

        System.IO.Stream IIconedObject.GetIconStreamPng(int hSize, int vSize, bool disabled, bool highlighted)
        {
            return ((IIconedObject)record).GetIconStreamPng(hSize, vSize, disabled, highlighted);
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (fields != null)
            {
                foreach (var field in fields)
                    field.Dispose();
                fields.Clear();
            }
        }

        #endregion
    }

    public class InfoViewEntryField: INotifyPropertyChanged, IDisposable
    {
        #region Private variables
        InfoViewEntry owner;
        InfoViewField field;
        private EventHandlerList events = null;
        private static PropertyChangedEventArgs valuePropertyChangedArgs = null;
        private static PropertyChangedEventArgs valueDisplayPropertyChangedArgs = null;
        #endregion Private variables;

        static InfoViewEntryField()
        {
        }

        public InfoViewEntryField(InfoViewEntry owner, InfoViewField field)
        {
            this.owner = owner;
            this.field = field;
        }

        public string Name
        {
            get { return field.Name; }
        }

        public string Title
        {
            get { return field.Title; }
        }

        public Type Type
        {
            get { return field.EffectiveType; }
        }

        public bool IsReadOnly
        {
            get { return field.IsReadOnly; }
        }

        public bool IsEnum
        {
            get { return field.IsEnum; }
        }

        public bool HasEditGroup
        {
            get { return field.EditGroup != null; }
        }

        public IEnumerable<InfoFieldEnumItem> EnumItems
        {
            get { return field.GetEnumItems(); }
        }

        public InfoFieldEnumItem GetEnumItemByValue(object value)
        {
            return field.GetEnumItemByValue(value);
        }

        public InfoFieldEnumItem GetEnumItemByTitle(string title)
        {
            return field.GetEnumItemByTitle(title);
        }

        public InfoViewField ReferencedField
        {
            get { return field.ReferencedField; }
        }

        public object Value
        {
            get 
            {
                if (valuePropertyChangedArgs == null)
                    valuePropertyChangedArgs = new PropertyChangedEventArgs("Value");
                return owner.GetFieldValue(field); 
            }
            set { owner.SetFieldValue(field, value); }
        }

        public object DisplayValue
        {
            get 
            {
                if (valueDisplayPropertyChangedArgs == null)
                    valueDisplayPropertyChangedArgs = new PropertyChangedEventArgs("DisplayValue");
                return owner.GetDisplayFieldValue(field); 
            }
        }

        private EventHandlerList Events
        {
            get
            {
                if (events == null)
                    events = new EventHandlerList();
                return events;
            }
        }

        #region INotifyPropertyChanged Members

        private static readonly object EVENT_PROPERTYCHANGED = new object();

        public event PropertyChangedEventHandler PropertyChanged
        {
            add { Events.AddHandler(EVENT_PROPERTYCHANGED, value); }
            remove { Events.RemoveHandler(EVENT_PROPERTYCHANGED, value); }
        }

        internal void FireValuePropertyChanged()
        {
            if (events == null)
                return;
            var handler = (PropertyChangedEventHandler)events[EVENT_PROPERTYCHANGED];
            if (handler != null)
            {
                if (valuePropertyChangedArgs != null)
                    handler(this, valuePropertyChangedArgs);
                if (valueDisplayPropertyChangedArgs != null)
                    handler(this, valueDisplayPropertyChangedArgs);
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (events != null)
                events.Dispose();
        }

        #endregion
    }

    public class InfoViewEntryFieldGroup
    {
        #region Private variables
        InfoViewEntry owner;
        InfoViewFieldGroup group;
        #endregion Private variables;

        public InfoViewEntryFieldGroup(InfoViewEntry owner, InfoViewFieldGroup group)
        {
            this.owner = owner;
            this.group = group;
        }

        public string Name
        {
            get { return group.Name; }
        }

        public string Title
        {
            get { return group.Title; }
        }

        public IEnumerable<InfoViewEntryField> Fields
        {
            get
            {
                foreach (var fld in group.Fields)
                    yield return new InfoViewEntryField(owner, fld);
            }
        }
    }
}
